package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

type stUser struct {
	strAcc string
	strPwd string
}

// 下单结构
type stOrderUI struct {
	LoginId     string
	Qty         uint32
	BuyOrSell   uint32
	BuildType   uint32
	MarketID    uint32
	GoodsCode   string
	RelateID    uint64
	RelateIDTxt string
	OrderPrice  float64
}

type OrderHandle func(d *stOrderUI)

var (
	exitChan  chan os.Signal
	userSlice []stUser
	usrConn   []*Session

	QuoteGoods []string
	uiCtrl     uiData
)

func main() {
	fmt.Println("---MTPClient_go---")

	// catch exit signal.
	{
		exitChan = make(chan os.Signal)
		signal.Notify(exitChan, os.Interrupt, os.Kill,
			syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)
		go exitHandle()
	}

	InitConfig("./config.xml")
	Stcfg.LocalIp = getLocalIP()

	PrintConfig()
	InitUser()
	InitErrMsgMap()
	InitQuoteGoods()
	InitEncrypto()
	InitLogObject()
	InitReqLog()

	err := checkNet()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 定时发送心跳包
	go SendHeart()

	LoginAll()

	uiCtrl.Do()

	time.Sleep(time.Hour * 10000)
}

func exitHandle() {
	s := <-exitChan
	fmt.Println("recv exit signal:", s)
	LogoutAll()
	os.Exit(1)
}

func InitUser() {
	fileName := "user.ini"
	userData, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Printf("read user from file[%v] fail:%v", fileName, err)
		return
	}

	tmpMap := make(map[string]string)

	vUser := strings.Split(string(userData), "\n")
	for _, u := range vUser {
		u = strings.Replace(u, " ", "", -1)
		u = strings.Replace(u, "\r", "", -1)
		if len(u) > 4 {
			buf := strings.Split(u, ",")
			if len(buf) == 2 {
				// 去重处理
				if _, ok := tmpMap[buf[0]]; !ok {
					userSlice = append(userSlice, stUser{buf[0], buf[1]})
					tmpMap[buf[0]] = buf[1]
				}
			}
		}
	}

	fmt.Printf("read user from file[%v], total:%d\n-------------------------------\n",
		fileName, len(userSlice))
}

func InitQuoteGoods() {

	if Stcfg.SubscribeQuote != 1 {
		return
	}

	fileName := "SubscribeQuote.ini"
	userData, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Printf("read quote goods from file[%v] fail:%v", fileName, err)
		return
	}

	tmpMap := make(map[string]string)

	vGoods := strings.Split(string(userData), "\n")
	for _, u := range vGoods {
		u = strings.Replace(u, " ", "", -1)
		u = strings.Replace(u, "\r", "", -1)

		if len(u) > 4 {
			// 去重处理
			if _, ok := tmpMap[u]; !ok {
				QuoteGoods = append(QuoteGoods, u)
				tmpMap[u] = "goods"
			}
		}
	}

	fmt.Printf("read quote goods from file[%v], total:%d\n-------------------------------\n",
		fileName, len(QuoteGoods))
}

func getLocalIP() string {
	nf, err := net.Interfaces()
	if err != nil {
		return "127.0.0.1"
	}

	for i := 0; i < len(nf); i++ {
		if (nf[i].Flags & net.FlagUp) != 0 {
			addrs, _ := nf[i].Addrs()
			for _, addr := range addrs {
				if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						return ipnet.IP.String()
					}
				}
			}
		}
	}

	return "127.0.0.1"
}

func checkNet() error {
	strIp := Stcfg.BizAddr()
	for i := 0; i < 10000; i++ {
		log.Printf("check connect server[%s] ...", strIp)
		_, err := net.Dial("tcp", strIp)
		if err != nil {
			log.Printf("connect server[%s] fail", strIp)
			time.Sleep(time.Second * 2)
			continue
		} else {
			log.Printf("connect server[%s] success!", strIp)
			return nil
		}
	}

	// 如果配置了订阅行情,检查行情链路
	if Stcfg.SubscribeQuote == 1 {
		log.Printf("check connect quote server[%v]", Stcfg.QuoteAddress)
		_, err := net.Dial("tcp", Stcfg.QuoteAddress)
		if err != nil {
			return fmt.Errorf("connect quote server fail")
		}
	}

	return fmt.Errorf("connect server[%s] time out", strIp)
}

func LoginAll() {
	if usrConn == nil {
		usrConn = make([]*Session, 0)
	}

	var nCount uint64 = 0

	for _, u := range userSlice {
		s := new(Session)
		usrConn = append(usrConn, s)

		if Stcfg.PrintLog != 0 {
			fmt.Println("user:", u.strAcc, " try login...")
		}

		go s.Do(u.strAcc, u.strPwd)
		time.Sleep(time.Millisecond * time.Duration(Stcfg.LoginInterval))
		if nCount++; nCount >= Stcfg.LoginMaxCount {
			fmt.Println("arrive max login limit:", Stcfg.LoginMaxCount)
			break
		}
	}
}

func LogoutAll() {

	if len(usrConn) == 0 {
		return
	}

	fmt.Println("prepare logout all")
	for _, s := range usrConn {
		s.logout()
	}

	// 最多等待5秒
	for i := 0; i < 5; i++ {
		logoutAll := true
		// 等待登出完成
		time.Sleep(time.Second * 1)
		for _, s := range usrConn {
			if s.IsLogin() {
				logoutAll = false
				continue
			}
		}
		if logoutAll {
			break
		}
	}
}

func SendHeart() {
	for i := 0; i < 1000000; i++ {
		time.Sleep(time.Second * 60)
		for _, s := range usrConn {
			s.SendHeart()
			s.SendTokenCheck()
			time.Sleep(time.Millisecond * 5)
		}
	}
}

func GetSession(strAcc string) *Session {
	for _, s := range usrConn {
		if s.strAcc == strAcc {
			return s
		}
	}

	return nil
}
